/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mundo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author cesarfgt
 */
public class Tramo implements Serializable {

    public static final int UNIDIRECCIONAL = 0;
    public static final int UNIDIRECCIONAL_INVERTIDA = 1;
    public static final int BIDIRECCIONAL = 2;
    public static final int Izquierdo = 0;
    public static final int Derecho = 1;
    public static final int Adelante = 1;
    public static final int Atras = 0;
    
    private Cruce CruceA;
    private Cruce CruceB;
    private int Direccion;
    private boolean Horizontal=false;
    private Punto InfIz;
    private Punto SupDer;
    private List<Punto> Camino_Derecho=new ArrayList();
    private List<Punto> Camino_Izquierdo=new ArrayList();
    
    public Tramo(Cruce CruceA, Cruce CruceB, int direccion) {
        this.Direccion = direccion;
        this.CruceA = CruceA;
        this.CruceA.addTramo(this);
        this.CruceB = CruceB;
        this.CruceB.addTramo(this);
        this.Horizontal = false;
        if (this.CruceA.getInfIz().getY() == this.CruceB.getInfIz().getY()) {
            //  Es un tramo horizontal
            this.Horizontal = true;
            this.InfIz = new Punto(this.CruceA.getSupDer().getX() + 1, this.CruceA.getInfIz().getY());
            this.SupDer = new Punto(this.CruceB.getInfIz().getX() - 1, this.CruceB.getSupDer().getY());
            
            for(int i=InfIz.getX();i<=SupDer.getX();i++){
                Camino_Derecho.add(new Punto(i,InfIz.getY()));
                Camino_Izquierdo.add(new Punto(i,SupDer.getY()));
            }

        } else {
            //  Es un tramo vertical
            this.Horizontal = false;
            this.InfIz = new Punto(this.CruceA.getInfIz().getX(), this.CruceA.getSupDer().getY() + 1);
            this.SupDer = new Punto(this.CruceB.getSupDer().getX(), this.CruceB.getInfIz().getY() - 1);
            
            for(int i=InfIz.getY();i<=SupDer.getY();i++){
                Camino_Derecho.add(new Punto(InfIz.getX(),i));
                Camino_Izquierdo.add(new Punto(SupDer.getX(),i));
            }
        }
    }

    /**
     * @return the CruceA
     */
    public Cruce getCruceA() {
        return CruceA;
    }

    /**
     * @return the CruceB
     */
    public Cruce getCruceB() {
        return CruceB;
    }

    /**
     * @return the Direccion
     */
    public int getDireccion() {
        return Direccion;
    }

    /**
     * @return the InfIz
     */
    public Punto getInfIz() {
        return InfIz;
    }

    /**
     * @return the SupDer
     */
    public Punto getSupDer() {
        return SupDer;
    }

    

    /**
     * @return the Horizontal
     */
    public boolean isHorizontal() {
        return Horizontal;
    }

    public List Camino(int carril) {
        if(carril==Tramo.Izquierdo){
            return this.Camino_Izquierdo;
        }
        if(carril==Tramo.Derecho){
            return this.Camino_Derecho;
        }
        return new ArrayList();
    }
    
    public int Camino(Punto p) {
        if(p.inPuntos(Camino_Izquierdo)){
            return Tramo.Izquierdo;
        }
        if(p.inPuntos(Camino_Derecho)){
            return Tramo.Derecho;
        }
        return -1;
    }
    
    public List getCamino_Izquierdo(){
        return Camino_Izquierdo;
    }
    
    public List getCamino_Derecho(){
        return Camino_Derecho;
    } 
    
    @Override
    public String toString() {
        String d="(";
        for(int i=0;i<Camino_Derecho.size();i++){
            d=d+","+Camino_Derecho.get(i);
        }
        d=d+")";
        String z="(";
        for(int i=0;i<Camino_Izquierdo.size();i++){
            z=z+","+Camino_Izquierdo.get(i);
        }
        z=z+")";
        return "H"+this.Horizontal+" InfIz="+this.InfIz+" SupDer="+this.SupDer+"Der"+d+"Izq"+z;
    }
    
    public Punto getNext(Punto ubicacion){
        int carril=Camino(ubicacion);
        //System.out.println("Carril->>>>>"+carril);
        if(carril!=-1){
            List <Punto>c=Camino(carril);
            if(carril==Tramo.Derecho){

                for(int i=0;i<c.size();i++){
                    //System.out.println("comparacion->"+c.get(i)+"=="+ubicacion);
                    if(c.get(i).equals(ubicacion)){
                        if(this.Horizontal){
                            if((i-1)>=0){
                                return c.get(i-1);
                            }
                        }else{
                            if((i+1)<c.size()){
                                return c.get(i+1); 
                            }
                        }

                    }
                }
            }else{
                for(int i=0;i<c.size();i++){
                    if(c.get(i).equals(ubicacion)){
                        //System.out.println("Is Horizontal"+this.Horizontal);
                        if(this.Horizontal){
                            if((i+1)<c.size()){
                                return c.get(i+1); 
                            } 
                        }else{
                            if((i-1)>=0){
                                return c.get(i-1);
                            } 
                        }
                    }
                }  
            }
        }
        
        Cruce cr=this.nearCruce(ubicacion);
        //System.out.println("nearCruce->>>>>"+cr);
        return ubicacion.Cercano(cr.getPuntos());
    }
    
    
    
    public boolean inTramo(Punto ubicacion){
        //int i=Integer.MAX_VALUE;
        if (getInfIz().getX() <= ubicacion.getX() && getInfIz().getY() <= ubicacion.getY()
                    && getSupDer().getX() >= ubicacion.getX() && getSupDer().getY() >= ubicacion.getY()) {
                return true;
            }
        return false;
    }
    
    public double Distancia(Punto ubicacion){
        double disMax=Double.MAX_VALUE;
        for(Punto p:this.Camino_Derecho){
            double temp=ubicacion.Distancia(p);
            if(temp<disMax){
                disMax=temp;
            }
        }
        for(Punto p:this.Camino_Izquierdo){
            double temp=ubicacion.Distancia(p);
            if(temp<disMax){
                disMax=temp;
            }
        }
        return disMax;
    }
    
    public Cruce nearCruce(Punto ubicacion){
        
        if(this.CruceA.Distancia(ubicacion)<this.CruceB.Distancia(ubicacion)){
            return this.CruceA;
        }
        return this.CruceB;
    }
    
    public Cruce getCruce(Punto ubicacion){
        
        if(this.CruceA.inCruce(ubicacion)){
            return this.CruceA;
        }
        if(this.CruceB.inCruce(ubicacion)){
            return this.CruceB;
        }
        return null;
        
    }
    
    
    public Punto irHaciaTramo(Punto ubicacion){
        Punto nuevoPunto=null;
        List <Punto> Puntos=this.Camino(Tramo.Derecho);
        Punto P=ubicacion.Cercano(Puntos);
        
        Cruce cr=this.nearCruce(ubicacion);
        nuevoPunto=P.Cercano(cr.getPuntos());
        
        Punto nuevoPunto2=this.getMovimiento(nuevoPunto,P);
        if(nuevoPunto2!=null){
            //System.out.println("Tramo.Derecho");
            if(nuevoPunto.equals(ubicacion)){
                return nuevoPunto2;
            }
            return nuevoPunto;
        }
        
        
        Puntos=this.Camino(Tramo.Izquierdo);
        P=ubicacion.Cercano(Puntos);
        
        nuevoPunto=P.Cercano(cr.getPuntos());
        
        nuevoPunto2=this.getMovimiento(nuevoPunto,P);
        if(nuevoPunto2!=null){
            //System.out.println("Tramo.Izquierdo");
            if(nuevoPunto.equals(ubicacion)){
                return nuevoPunto2;
            }
            return nuevoPunto;
        }
        //System.out.println("Tramo.None");
        /*
        nuevoPunto=this.getMovimiento(ubicacion,P);
        if(nuevoPunto!=null){
            //System.out.println("Derecho!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            return nuevoPunto;
        }
        Puntos=this.Camino(Tramo.Izquierdo);
        P=ubicacion.Cercano(Puntos);
        
        //System.out.println("Izquierdo!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        
        nuevoPunto=this.getMovimiento(ubicacion,P);
        */
        
        return null;
    }

   
    
    private boolean isPosible(Punto ubicacion, Punto nuevoPunto) {
       Punto p=getNext(nuevoPunto);
       //System.out.println(p+"@nuevoPunto"+nuevoPunto+"@ubicacion"+ubicacion);
       if(p==null){
           return false;
       }else if(p.equals(ubicacion)){
           return false;
       }

       return true;
    }

    private Punto getMovimiento(Punto ubicacion, Punto P) {
        Punto nuevoPunto=null;
        if(P.getX()>ubicacion.getX()){
            nuevoPunto=new Punto(ubicacion.getX()+1,ubicacion.getY());
            if(this.isPosible(ubicacion,nuevoPunto)){
                return nuevoPunto;
            }
        }
        
        if(P.getX()<ubicacion.getX()){
            nuevoPunto=new Punto(ubicacion.getX()-1,ubicacion.getY());
            if(this.isPosible(ubicacion,nuevoPunto)){
                return nuevoPunto;
            }
        }
        
        if(P.getY()>ubicacion.getY()){
            nuevoPunto=new Punto(ubicacion.getX(),ubicacion.getY()+1);
            if(this.isPosible(ubicacion,nuevoPunto)){
                return nuevoPunto;
            }
        }
        
        if(P.getY()<ubicacion.getY()){
            nuevoPunto=new Punto(ubicacion.getX(),ubicacion.getY()-1);
            if(this.isPosible(ubicacion,nuevoPunto)){
                return nuevoPunto;
            }
        }
        return null;
    }
 
    
    
}
